package com.zimin.cloud.webflux.handler;

import com.alibaba.fastjson.JSON;
import com.zimin.common.exception.InjectException;
import com.zimin.shared.enums.ResponseStatusEnum;
import com.zimin.shared.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * webflux 全局异常异常处理
 * 1、{@link org.springframework.web.bind.annotation.RestControllerAdvice} 注解在响应式编程WebFlux中不生效，所以需要自定义处理。
 * 2、{@link ErrorWebExceptionHandler} 接口会处理异常，所以我们需要实现 #handle 方法并返回自定义的格式
 *
 * @author zimin
 * @since 2022/3/22 3:41 下午
 */
@Slf4j
@Configuration
@Order(-1)
public class ExceptionHandler implements ErrorWebExceptionHandler {
    private Integer code;
    private String msg;
    private Boolean success;

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpResponse response = exchange.getResponse();
        code = ResponseStatusEnum.FAILED.status();
        msg = ex.getMessage();
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        }

        if (ex instanceof InjectException) {
            InjectException e = (InjectException) ex;
            code = e.getCode();
            msg = e.getMsg();
            success = Boolean.FALSE;
        } else {
            code = ResponseStatusEnum.SERVER_BUY.status();
            msg = ResponseStatusEnum.SERVER_BUY.msg();
            success = Boolean.FALSE;
        }
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.setStatusCode(HttpStatus.OK);
        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory bufferFactory = response.bufferFactory();
            return bufferFactory.wrap(JSON.toJSONBytes(Result.ok(code, msg, success)));
        }));
    }

}
